package com.morpheus.redis.redisson.api.lock.multi;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;

import org.apache.commons.collections4.MapUtils;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.morpheus.redis.redisson.api.lock.MultiLock;

public class MultiDistributedLock implements MultiLock {
	private static final Logger LOGGER = LoggerFactory.getLogger(MultiDistributedLock.class);

	private Map<String, RLock> lockMap = new ConcurrentHashMap<String, RLock>();
	private RedissonClient redissonClient = null;

	public MultiDistributedLock(RedissonClient redissonClient) {
		this.redissonClient = redissonClient;
	}

	@Override
	public void lock(String lockName) {
		try {
			RLock rlock = null;
			if (this.lockMap.containsKey(lockName)) {
				rlock = this.lockMap.get(lockName);
			} else {
				rlock = this.redissonClient.getLock(lockName);
				this.lockMap.put(lockName, rlock);
			}
			if (rlock != null) {
				rlock.lock();
			}
		} catch (Throwable th) {
			LOGGER.error("MultiDistributedLock.lock(lockName) throwable", th);
		}
	}

	@Override
	public void lock(String lockName, long time, TimeUnit unit) throws InterruptedException {
		try {
			RLock rlock = null;
			if (this.lockMap.containsKey(lockName)) {
				rlock = this.lockMap.get(lockName);
			} else {
				rlock = this.redissonClient.getLock(lockName);
				this.lockMap.put(lockName, rlock);
			}
			if (rlock != null) {
				rlock.lock(time, unit);
			}
		} catch (Throwable th) {
			LOGGER.error("MultiDistributedLock.lock(lockName, time, unit) throwable", th);
		}
	}

	@Override
	public void lockInterruptibly(String lockName) throws InterruptedException {
		RLock rlock = null;
		if (this.lockMap.containsKey(lockName)) {
			rlock = this.lockMap.get(lockName);
		} else {
			rlock = this.redissonClient.getLock(lockName);
			this.lockMap.put(lockName, rlock);
		}
		if (rlock != null) {
			rlock.lockInterruptibly();
		}
	}

	@Override
	public Condition newCondition(String lockName) {
		RLock rlock = null;
		if (this.lockMap.containsKey(lockName)) {
			rlock = this.lockMap.get(lockName);
		} else {
			rlock = this.redissonClient.getLock(lockName);
			this.lockMap.put(lockName, rlock);
		}
		Condition condition = null;
		if (rlock != null) {
			condition = rlock.newCondition();
		}
		return condition;
	}

	@Override
	public boolean tryLock(String lockName) {
		try {
			RLock rlock = null;
			if (this.lockMap.containsKey(lockName)) {
				rlock = this.lockMap.get(lockName);
			} else {
				rlock = this.redissonClient.getLock(lockName);
				this.lockMap.put(lockName, rlock);
			}
			if (rlock != null) {
				boolean flag = rlock.tryLock();
				return flag;
			}
		} catch (Throwable th) {
			LOGGER.error("MultiDistributedLock.tryLock(lockName) throwable", th);
		}
		return false;
	}

	@Override
	public boolean tryLock(String lockName, long time, TimeUnit unit) throws InterruptedException {
		try {
			RLock rlock = null;
			if (this.lockMap.containsKey(lockName)) {
				rlock = this.lockMap.get(lockName);
			} else {
				rlock = this.redissonClient.getLock(lockName);
				this.lockMap.put(lockName, rlock);
			}
			if (rlock != null) {
				boolean flag = rlock.tryLock(time, unit);
				return flag;
			}
		} catch (Throwable th) {
			LOGGER.error("MultiDistributedLock.tryLock(lockName, time, unit) throwable", th);
		}
		return false;
	}

	@Override
	public synchronized void unlock(String lockName) {
		RLock rlock = null;
		try {
			if (this.lockMap.containsKey(lockName)) {
				rlock = this.lockMap.get(lockName);
			} else {
				rlock = this.redissonClient.getLock(lockName);
				this.lockMap.put(lockName, rlock);
			}
			if (rlock != null && rlock.isLocked()) {
				rlock.forceUnlock();
			}
		} catch (Throwable th) {
			LOGGER.error("MultiDistributedLock.unlock() throwable", th);
			throw new IllegalStateException(th);
		} finally {
			this.destory(lockName);
		}
	}

	@Override
	public void destory(String lockName) {
		if (MapUtils.isEmpty(this.lockMap)) {
			this.lockMap.clear();
			this.lockMap = null;
			this.redissonClient = null;
		}
		LOGGER.warn("Multi lock is not empty, curatorFramework cann't be destoried");
	}
}
